﻿using System;
using UnityEditor;
using UnityEngine;

public class SwingableFadeShaderEditor : ShaderGUI
{

    public enum CullMode
    {
        CULL_NONE = 0,
        CULL_FRONT = 1,
        CULL_BACK = 2,
    }

    public enum BlendMode
    {
        Opaque,
        Cutout,
        Fade,   // Old school alpha-blending mode, fresnel does not affect amount of transparency
        Transparent // Physically plausible transparency mode, implemented as alpha pre-multiply
    }


    private static class Styles
    {
        public static GUIContent uvSetLabel = new GUIContent("UV Set");

        public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
        public static GUIContent alphaCutoffText = new GUIContent("Alpha Cutoff", "Threshold for alpha cutoff");
        public static GUIContent specularMapText = new GUIContent("Specular", "Specular (RGB) and Smoothness (A)");
        public static GUIContent metallicMapText = new GUIContent("Metallic", "Metallic (R) and Smoothness (A)");
        public static GUIContent smoothnessText = new GUIContent("Smoothness", "Smoothness value");
        public static GUIContent smoothnessScaleText = new GUIContent("Smoothness", "Smoothness scale factor");
        public static GUIContent smoothnessMapChannelText = new GUIContent("Source", "Smoothness texture and channel");
        public static GUIContent highlightsText = new GUIContent("Specular Highlights", "Specular Highlights");
        public static GUIContent reflectionsText = new GUIContent("Reflections", "Glossy Reflections");
        public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map");
        public static GUIContent heightMapText = new GUIContent("Height Map", "Height Map (G)");
        public static GUIContent occlusionText = new GUIContent("Occlusion", "Occlusion (G)");
        public static GUIContent emissionText = new GUIContent("Color", "Emission (RGB)");
        public static GUIContent detailMaskText = new GUIContent("Detail Mask", "Mask for Secondary Maps (A)");
        public static GUIContent detailAlbedoText = new GUIContent("Detail Albedo x2", "Albedo (RGB) multiplied by 2");
        public static GUIContent detailNormalMapText = new GUIContent("Normal Map", "Normal Map");

        public static string primaryMapsText = "Main Maps";
        public static string secondaryMapsText = "Secondary Maps";
        public static string forwardText = "Forward Rendering Options";
        public static string renderingMode = "Rendering Mode";
        public static string advancedText = "Advanced Options";
        public static readonly string[] blendNames = Enum.GetNames(typeof(BlendMode));
    }

    MaterialProperty blendMode = null;
    MaterialEditor m_MaterialEditor;

    void BlendModePopup()
    {
        EditorGUI.showMixedValue = blendMode.hasMixedValue;
        var mode = (BlendMode)blendMode.floatValue;

        EditorGUI.BeginChangeCheck();
        mode = (BlendMode)EditorGUILayout.Popup(Styles.renderingMode, (int)mode, Styles.blendNames);
        if (EditorGUI.EndChangeCheck())
        {
            m_MaterialEditor.RegisterPropertyChangeUndo("Rendering Mode");
            blendMode.floatValue = (float)mode;
        }

        EditorGUI.showMixedValue = false;
    }


    public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)
    {
        switch (blendMode)
        {
            case BlendMode.Opaque:
                material.SetOverrideTag("RenderType", "CurvedWorld_Opaque");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = -1;
                break;
            case BlendMode.Cutout:
                material.SetOverrideTag("RenderType", "CurvedWorld_TransparentCutout");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.EnableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;
                break;
            case BlendMode.Fade:
                material.SetOverrideTag("RenderType", "Transparent");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
                break;
            case BlendMode.Transparent:
                material.SetOverrideTag("RenderType", "Transparent");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
                break;
        }
    }

    public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
    {
        Shader.SetGlobalFloat(ShaderConst.SID_RoleDistance, 0);
        m_MaterialEditor = materialEditor;

        Material targetMat = materialEditor.target as Material;

        blendMode = FindProperty("_Mode", properties);

        base.OnGUI(materialEditor, properties);
        bool USE_FADE = Array.IndexOf(targetMat.shaderKeywords, "USE_FADE") != -1;
        bool USE_ALPHA_FADE = Array.IndexOf(targetMat.shaderKeywords, "USE_ALPHA_FADE") != -1;

        EditorGUI.BeginChangeCheck();
        {

            BlendModePopup();

            USE_FADE = EditorGUILayout.ToggleLeft("遮挡透明淡出", USE_FADE);
            bool USE_SWING = Array.IndexOf(targetMat.shaderKeywords, "USE_SWING") != -1;
            bool USE_SSS = Array.IndexOf(targetMat.shaderKeywords, "USE_SSS") != -1;
            //var alpha = 1f;
            targetMat.EnableKeyword("USE_TEXTURE");
            for (int i = 0; i < properties.Length; i++)
            {
                var prop = properties[i];
                if (prop.name == "_MainTex")
                {
                    bool USE_TEXTURE = prop.textureValue != null;
                    if (USE_TEXTURE)
                        targetMat.EnableKeyword("USE_TEXTURE");
                    else
                        targetMat.DisableKeyword("USE_TEXTURE");
                }
                else if (prop.name == "_EmissionTex")
                {
                    bool USER_EMISSION_TEXTURE = prop.textureValue != null;
                    if (USER_EMISSION_TEXTURE)
                        targetMat.EnableKeyword("USER_EMISSION_TEXTURE");
                    else
                        targetMat.DisableKeyword("USER_EMISSION_TEXTURE");
                }
                else if (prop.name == "_BumpMap")
                {
                    var USE_BUMP_TEXTURE = prop.textureValue != null;
                    if (USE_BUMP_TEXTURE)
                        targetMat.EnableKeyword("USE_BUMP_TEXTURE");
                    else
                        targetMat.DisableKeyword("USE_BUMP_TEXTURE");
                }
                else if (prop.name == "_Alpha")
                {
                    EditorGUILayout.BeginHorizontal(GUI.skin.box, GUILayout.ExpandWidth(true));
                    USE_ALPHA_FADE = EditorGUILayout.ToggleLeft(prop.displayName, USE_ALPHA_FADE, GUILayout.Width(80));
                    if (USE_ALPHA_FADE)
                    {
                        prop.floatValue = EditorGUILayout.Slider(prop.floatValue, 0f, 1f);
                    }
                    EditorGUILayout.EndHorizontal();
                }
                //else if (prop.name == "_FixedColor")
                //{
                //    prop.colorValue = EditorGUILayout.ColorField(prop.displayName, prop.colorValue);
                //}
                else if (prop.name == "_ShakeIntensity")
                {
                    //EditorGUILayout.BeginHorizontal();
                    //EditorGUILayout.BeginVertical(GUI.skin.box, GUILayout.ExpandWidth(true));
                    USE_SWING = EditorGUILayout.ToggleLeft("摇摆", USE_SWING, GUILayout.Width(80));
                    if (USE_SWING)
                    {
                        prop.floatValue = EditorGUILayout.Slider(prop.displayName,
                            prop.floatValue, prop.rangeLimits.x, prop.rangeLimits.y);
                    }
                    //EditorGUILayout.EndHorizontal();
                }
                else if (prop.name == "_ShakePosScale")
                {
                    if (USE_SWING)
                        prop.floatValue = EditorGUILayout.FloatField(prop.displayName, prop.floatValue);
                }
                else if (prop.name == "_Softness")
                {
                    if (USE_SWING)
                        prop.floatValue = EditorGUILayout.FloatField(prop.displayName, prop.floatValue);
                    //EditorGUILayout.EndVertical();
                }
                else if (prop.name == "_SSSStrength")
                {
                    EditorGUILayout.BeginVertical(GUI.skin.box, GUILayout.ExpandWidth(true));
                    USE_SSS = EditorGUILayout.ToggleLeft("次表面散射", USE_SSS, GUILayout.Width(80));
                    if (USE_SSS)
                    {
                        prop.floatValue = EditorGUILayout.Slider("强度", prop.floatValue, 0, 10);
                    }
                    EditorGUILayout.EndVertical();
                }
            }

            //cullMode
            var cullMode = FindProperty("_Cull", properties);
            GUILayout.BeginHorizontal();
            GUILayout.Label(new GUIContent("Cull", "CullMode"), GUILayout.Width(120));
            var cull = (CullMode)cullMode.floatValue;
            cull = (CullMode)EditorGUILayout.Popup((int)cull, Enum.GetNames(typeof(CullMode)));
            GUILayout.EndHorizontal();
            bool ALWAYS_FACE_CAMERA = Array.IndexOf<string>(targetMat.shaderKeywords, "ALWAYS_FACE_CAMERA") != -1;
            ALWAYS_FACE_CAMERA = EditorGUILayout.ToggleLeft("法线始终朝向镜头", ALWAYS_FACE_CAMERA);

            if (EditorGUI.EndChangeCheck())
            {
                if (USE_FADE)
                    targetMat.EnableKeyword("USE_FADE");
                else
                    targetMat.DisableKeyword("USE_FADE");
                if (USE_ALPHA_FADE)
                    targetMat.EnableKeyword("USE_ALPHA_FADE");
                else
                    targetMat.DisableKeyword("USE_ALPHA_FADE");
                if (ALWAYS_FACE_CAMERA)
                    targetMat.EnableKeyword("ALWAYS_FACE_CAMERA");
                else
                    targetMat.DisableKeyword("ALWAYS_FACE_CAMERA");
                if (USE_SWING)
                    targetMat.EnableKeyword("USE_SWING");
                else
                    targetMat.DisableKeyword("USE_SWING");
                if (USE_SSS)
                    targetMat.EnableKeyword("USE_SSS");
                else
                    targetMat.DisableKeyword("USE_SSS");

                //cullMode
                cullMode.floatValue = (float)cull;
                targetMat.SetInt("_Cull", (int)cull);

                SetupMaterialWithBlendMode(targetMat, (BlendMode)targetMat.GetFloat("_Mode"));

                //if (USE_ALPHA_FADE)
                //    targetMat.SetFloat("_Alpha", alpha);

            }
        }


    }

}